import { state } from '@angular/animations';
import { Component, forwardRef, OnDestroy, OnInit, Renderer2 } from '@angular/core'
import { CascaderPoprs, Option } from './cascader-props'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'

@Component({
  selector: 'cascader',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => Cascader),
    multi: true
  }],
  template: `
    <span
    [class]="'el-cascader ' +  (menuVisible ? 'is-opened ' : '') + (elDisabled ? 'is-disabled ' : '')+ (size ? 'el-cascader--' + size : '')"
       [style]="{'width':(width==0?'100%':(width+'px'))}"
      (click)="clickHandle($event)"
      (mouseenter)="inputHover = true" (mouseleave)="inputHover = false">
      <div style="display:flex;cursor:pointer;position:relative;" class="p-dropdown p-component" [class]="{'p-focus':menuVisible}"  [style]="{'width':(width==0?'100%':(width+'px'))}">
      <input  [readonly]="true"  class="p-dropdown-label p-inputtext" style="cursor:pointer;"
        [placeholder]="currentLabels.length ? '' : placeholder"

     />
     <i class="p-dropdown-clear-icon pi pi-times ng-tns-c55-23 ng-star-inserted" *ngIf="clearable" (click)="clearValue($event)"></i>
     <div role="button" aria-haspopup="listbox" class="p-dropdown-trigger ng-tns-c55-5"><span class="p-dropdown-trigger-icon ng-tns-c55-5 pi pi-chevron-down" ng-reflect-ng-class="pi pi-chevron-down"></span></div>
     </div>
      <span class="el-cascader__label" *ngIf="currentLabels.length">
        <ng-container *ngIf="allLevels">
          <ng-container *ngFor="let item of currentLabels; let i = index">
            {{ item.label }}
            <span *ngIf="i < currentLabels.length - 1"> / </span>
          </ng-container>
        </ng-container>
        <ng-container *ngIf="!allLevels">
          {{ currentLabels[currentLabels.length - 1].label }}
        </ng-container>
      </span>
      <cascader-menu></cascader-menu>
  </span>
  `,
})
export class Cascader extends CascaderPoprs implements OnInit, OnDestroy, ControlValueAccessor {

  steps: any[] = []
  menuVisible: boolean = false
  inputHover: boolean = false
  currentLabels: Option[] = []
  globalListenFunc: Function

  constructor(
    private renderer: Renderer2,
  ) {
    super()
  }

  close(): void {
    this.menuVisible = false
    this.globalListenFunc && this.globalListenFunc()
  }

  clickHandle(event: MouseEvent): void {
    event.stopPropagation()
    if (this.elDisabled) return

    const element: HTMLElement = event.target as HTMLElement
    const isSelfTrigger = ['SPAN', 'I', 'INPUT', 'DIV'].find(v => v === element.tagName)
    if (!isSelfTrigger) return
    this.menuVisible = !this.menuVisible

    if (this.menuVisible) {
      this.globalListenFunc = this.renderer.listen(
        'document', 'click', () => {
          this.menuVisible = false
        }
      )
    } else {
      this.globalListenFunc && this.globalListenFunc()
    }
  }

  changeLabels(): void {
    const nextValue: Option[] = []
    this.steps.forEach((items: Option[]) => {
      const steps: Option[] = items.filter((item: Option) => item.active)
      nextValue.push(steps[0])
    })
    this.currentLabels = nextValue
    const next = nextValue.map((item: Option) => item.value)
    this.model = next
    this.modelChange.emit(next)
    this.controlChange(next)
  }

  clearValue(event?: Event): void {
    event && event.stopPropagation()
    this.currentLabels = []
    const step1 = this.options.map((option: Option) =>
      Object.assign(option, {
        active: false,
      }))
    this.steps = [step1]
    this.menuVisible = false
  }



  selectHandle(event: Event, step: number, index: number): any {
    event.stopPropagation()

    if (this.steps[step][index].elDisabled) return
    this.steps[step] = this.steps[step].map((item: Option, i: number) =>
      Object.assign(item, { active: i === index }))
    // reset steps
    this.steps.length = step + 1
    const next = this.steps[step][index].children

    // go next
    if (next && Array.isArray(next)) {
      // change on select (props)
      this.changeOnSelect && this.changeLabels()
      const nativeNext = next.map((item: Option) => Object.assign(item, { active: false }))
      return this.steps.push(nativeNext)
    }
    // last step
    this.changeLabels()
    this.menuVisible = false
  }

  showClearIcon(): boolean {
    return !!(this.clearable && this.inputHover && this.currentLabels.length)
  }

  ngOnInit(): void {
    this.clearValue()
    if (this.model && this.model.length) {
      const getLabel = (options: Option[], val: string) => {
        const item: Option = options.filter((item: Option) => item.value === val)[0]
        return { children: item.children, val: item }
      }

      let options: Option[] = this.options
      const val: Option[] = this.model.map(v => {
        const { children, val } = getLabel(options, v)
        options = children
        return val
      })
      this.currentLabels = val.filter(v => !!v)
    }
  }

  ngOnDestroy(): void {
    this.globalListenFunc && this.globalListenFunc()
  }

  writeValue(value: any): void {
    this.model = value
  }

  registerOnChange(fn: Function): void {
    this.controlChange = fn
  }

  registerOnTouched(fn: Function): void {
    this.controlTouch = fn
  }

  private controlChange: Function = () => {}
  private controlTouch: Function = () => {}

}
